/** for Universe */
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

/**
 * This is Universe class that have whole planets.
 * @author CodeTrader
 * @version 1.0
 */
public class Universe implements Serializable {
	
	/**
	 * serialVersionUID for the Universe class
	 */
	private static final long serialVersionUID = 1839489604474963730L;
	
	/**
	 * ArrayList holding the planets
	 */
	private List<Planet> planets = new ArrayList<Planet>();

	/**
	 * Constructor for the Universe. 
	 * Creates the universe by creating n number
	 *  of planet with random names from the array. 
	 * 
	 * @param n number of planets to be created
	 */
	public Universe(int n) {
		final String[] planet_names = {
			    "Acamar",
			    "Adahn",
			    "Aldea",
			    "Andevian",
			    "Antedi",
			    "Balosnee",
			    "Baratas",
			    "Brax",
			    "Bretel",
			    "Calondia",
			    "Campor",
			    "Capelle",
			    "Carzon",
			    "Castor",
			    "Cestus",
			    "Cheron",
			    "Courteney",
			    "Daled",
			    "Damast",
			    "Davlos",
			    "Deneb",
			    "Deneva",
			    "Devidia",
			    "Draylon",
			    "Drema",
			    "Endor",
			    "Esmee",		// One of the witches in Pratchett's Discworld
			    "Exo",
			    "Ferris",		// Iron
			    "Festen",		// A great Scandinavian movie
			    "Fourmi",		// An ant, in French
			    "Frolix",		// A solar system in one of Philip K. Dick's novels
			    "Gemulon",
			    "Guinifer",		// One way of writing the name of king Arthur's wife
			    "Hades",		// The underworld
			    "Hamlet",		// From Shakespeare
			    "Helena",		// Of Troy
			    "Hulst",		// A Dutch plant
			    "Iodine",		// An element
			    "Iralius",
			    "Janus",		// A seldom encountered Dutch boy's name
			    "Japori",
			    "Jarada",
			    "Jason",		// A Greek hero
			    "Kaylon",
			    "Khefka",
			    "Kira",			// My dog's name
			    "Klaatu",		// From a classic SF movie
			    "Klaestron",
			    "Korma",		// An Indian sauce
			    "Kravat",		// Interesting spelling of the French word for "tie"
			    "Krios",
			    "Laertes",		// A king in a Greek tragedy
			    "Largo",
			    "Lave",			// The starting system in Elite
			    "Ligon",
			    "Lowry",		// The name of the "hero" in Terry Gilliam's "Brazil"
			    "Magrat",		// The second of the witches in Pratchett's Discworld
			    "Malcoria",
			    "Melina",
			    "Mentar",		// The Psilon home system in Master of Orion
			    "Merik",
			    "Mintaka",
			    "Montor",		// A city in Ultima III and Ultima VII part 2
			    "Mordan",
			    "Myrthe",		// The name of my daughter
			    "Nelvana",
			    "Nix",			// An interesting spelling of a word meaning "nothing" in Dutch
			    "Nyle",			// An interesting spelling of the great river
			    "Odet",
			    "Og",			// The last of the witches in Pratchett's Discworld
			    "Omega",		// The end of it all
			    "Omphalos",		// Greek for navel
			    "Orias",
			    "Othello",		// From Shakespeare
			    "Parade",		// This word means the same in Dutch and in English
			    "Penthara",
			    "Picard",		// The enigmatic captain from ST:TNG
			    "Pollux",		// Brother of Castor
			    "Quator",
			    "Rakhar",
			    "Ran",			// A film by Akira Kurosawa
			    "Regulas",
			    "Relva",
			    "Rhymus",
			    "Rochani",
			    "Rubicum",		// The river Ceasar crossed to get into Rome
			    "Rutia",
			    "Sarpeidon",
			    "Sefalla",
			    "Seltrice",
			    "Sigma",
			    "Sol",			// That's our own solar system
			    "Somari",
			    "Stakoron",
			    "Styris",
			    "Talani",
			    "Tamus",
			    "Tantalos",		// A king from a Greek tragedy
			    "Tanuga",
			    "Tarchannen",
			    "Terosa",
			    "Thera",		// A seldom encountered Dutch girl's name
			    "Titan",		// The largest moon of Jupiter
			    "Torin",		// A hero from Master of Magic
			    "Triacus",
			    "Turkana",
			    "Tyrus",
			    "Umberlee",		// A god from AD&D, which has a prominent role in Baldur's Gate
			    "Utopia",		// The ultimate goal
			    "Vadera",
			    "Vagra",
			    "Vandor",
			    "Ventax",
			    "Xenon",
			    "Xerxes",		// A Greek hero
			    "Yew",			// A city which is in almost all of the Ultima games
			    "Yojimbo",		// A film by Akira Kurosawa
			    "Zalkon",
			    "Zuul"			// From the first Ghostbusters movie
			};
		final List<String> planet_array = new ArrayList<String>();
		for (int i = 0; i < planet_names.length; i++) {
			planet_array.add(planet_names[i]);
		}
		final List<String> planet_list = new ArrayList<String>();
		final Random rand = new Random();
		for (int i = 0; i < n; i++) {
			String planet_name = planet_array.get(rand.nextInt(planet_array.size()));
			planet_list.add(planet_name);
			planet_array.remove(planet_name);
		}
		Collections.shuffle(planet_list);
		final List<Point> pts = new ArrayList<Point>();
		for (int i = 0; i < planet_list.size(); i++) {
			Point pt;
			boolean found;
			// makes sure that the planets don't overlap
			do {
				pt = new Point(
						rand.nextInt(
								Numbers.FIVE_HUNDRED.getNumber() 
								+ Numbers.EIGHTY.getNumber()) 
								+ Numbers.TWENTY.getNumber(), 
						rand.nextInt(Numbers.HUNDRED_EIGHTY.getNumber()) 
									+ Numbers.THIRTY.getNumber());
				found = false;
				for (Point p : pts) {
					if (Math.sqrt(
							Math.pow(pt.x - p.x, Numbers.TWO.getNumber()) 
							+ Math.pow(pt.y - p.y, Numbers.TWO.getNumber())) 
							< Numbers.THIRTY.getNumber()) {
						found = true;
						break;
					}
				}
			} while (found);
			pts.add(pt);
			planets.add(new Planet(planet_list.get(i), pt.getX(), pt.getY()));
		}
	}
	
	/**
	 * This is a point class with x,y coordinates
	 * @author CodeTrader
	 *
	 */
	public static class Point {
		
		/**
		 * The x and the y coordinates of the Point
		 */
		private final int x, y;
		
		/**
		 * Point constructor
		 * @param x
		 * @param y
		 */
		public Point (int x, int y){
			this.x = x;
			this.y = y;
		}
		
		/**
		 * This is to get x coordinate
		 * @return x
	     */
		public int getX() {
			return this.x;
		}
		
		/**
		 * This is to get y coordinate
		 * @return y
		 */
		public int getY() {
			return this.y;
		}
		
		/**
		 * This is to check equal between coordinates
		 * @param p
		 * @return true or false.
		 */
		@Override
		public boolean equals(Object p) {
			if (p == this) return true;
			if (p != null && p instanceof Point) {
				return this.x == ((Point) p).x && this.y == ((Point) p).y;
			} else {
				return false;
			}
		}
		
		/**
		 * returns hashcode of the object
		 * 
		 * @return hash code of the object
		 */
		@Override
		public int hashCode() {
			return super.hashCode();
		}
		
		/** 
		 * This is a tostring method.
		 * @return tostring.
		 */
		@Override
		public String toString() {
			return super.toString();
		}
	}
	
	/**
	 * Constructor for the Universe. 
	 * Creates the universe by creating 30 (default)
	 *  planets with random names from the array.
	 */
	public Universe() {
		this(Numbers.THIRTY.getNumber());
	}
	
	/**
	 * Getter for the list of Planets
	 * 
	 * @return list of planets
	 */
	public List<Planet> getPlanets() {
		return this.planets;
	}
	
	/**
	 * Setter for the list of Planets
	 * 
	 * @param planets list of Planets
	 */
	public void setPlanets(List<Planet> planets) {
		this.planets = planets;
	}
	
	/**
	 * This is to get distance between two points.
	 * @param p1
	 * @param p2
	 * @return distance
	 */
	public double getDistance(Point p1, Point p2) {
		return Math.sqrt(Math.pow(p1.getX() - p2.getX(), Numbers.TWO.getNumber())
				+ Math.pow(p1.getY() - p2.getY(), Numbers.TWO.getNumber()));
	}

	/** 
	 * This is a tostring method.
	 * @return tostring.
	 */
	@Override
	public String toString() {
		return super.toString();
	}
}
